﻿using XUCore.WeChat.Apis;
using XUCore.WeChat.Apis.CustomerService;
using XUCore.WeChat.Apis.Media;
using XUCore.WeChat.Apis.Menu;
using XUCore.WeChat.Apis.Message;
using XUCore.WeChat.Apis.Sns;
using XUCore.WeChat.Apis.Token;
using XUCore.WeChat.Apis.User;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using XUCore.Extensions;
using XUCore.WeChat.App;
using Essensoft.Paylink.WeChatPay;
using Microsoft.Extensions.Caching.Distributed;
using System.Text;
using XUCore.WeChat.Net.ServerMessages;

namespace XUCore.WeChat
{
    public static class Extentions
    {
        /// <summary>
        /// 添加微信支付操作服务
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddWeChatPayService(this IServiceCollection services)
        {
            services.AddScoped<WeChatPayRsaService>();
            services.AddScoped<WeChatPayService>();

            return services;
        }

        /// <summary>
        /// 添加微信（公众号和小程序）Sdk集成
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddWeChatSdk(this IServiceCollection services)
        {
            services
                .AddWebApiClient()
                .UseJsonFirstApiActionDescriptor();

            services.AddSingleton<WeChatFuncs>();
            services.AddHttpApi<ITokenApi>();
            services.AddHttpApi<ITicketApi>();
            services.AddHttpApi<IOauth2Api>();
            services.AddHttpApi<ISnsApi>();
            services.AddHttpApi<ITemplateApi>();
            services.AddHttpApi<IMenuApi>();
            services.AddHttpApi<IKfAccountApi>();
            services.AddHttpApi<IMediaApi>();
            services.AddHttpApi<IUserApi>();
            services.AddHttpApi<ITagsApi>();


            services.AddSingleton<IWeChatTokenManager, WeChatTokenManager>();
            services.AddSingleton<IWeChatTicketManager, WeChatTicketManager>();
            services.AddSingleton<IWeChatWebSignature, WeChatWebSignature>();

            services.AddSingleton<IWeChatMiniProgramDecrypt, WeChatMiniProgramDecrypt>();

            return services;
        }

        /// <summary>
        /// 添加微信服务器事件消息处理程序
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddWeChatServerMessageHandler(this IServiceCollection services)
        {
            services.AddSingleton<ServerMessageHandler>();

            return services;
        }

        /// <summary>
        /// 配置公众号Sdk和支付sdk配置
        /// </summary>
        /// <param name="app"></param>
        /// <param name="setupAction"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseWeChatSdk(this IApplicationBuilder app, Action<WeChatFuncs> setupAction = null)
        {
            WeChatFuncs funcs = app.ApplicationServices.GetRequiredService<WeChatFuncs>();
            setupAction?.Invoke(funcs);

            //如果没有设置获取微信配置逻辑，则自动从配置文件读取

            //微信公众号的配置获取
            if (funcs.GetWeChatOptions == null)
            {
                IConfiguration config = app.ApplicationServices.GetRequiredService<IConfiguration>();
                IConfigurationSection wechatConfig = config.GetSection("WeChat");

                if (wechatConfig == null) throw new WeChatSdkException($"WeChat 为空，请检查配置");

                funcs.GetWeChatOptions = (app) =>
                {
                    var section = app.NotEmpty() ? $":{app}" : "";

                    IConfigurationSection _config = config.GetSection($"{WeChatConsts.CONFIG_SECTION_PUBLICACCOUNT_KEY}{section}");
                    if (_config == null) throw new WeChatSdkException($"{WeChatConsts.CONFIG_SECTION_PUBLICACCOUNT_KEY}{section} 为空，请检查配置");

                    return new WeChatPublicAccountOption()
                    {
                        AppId = _config["AppId"],
                        AppSecret = _config["AppSecret"],
                        Token = _config["Token"],
                        EncodingAESKey = _config["EncodingAESKey"],
                        WeChatPayOptions = new WeChatPayOptions
                        {
                            AppId = _config["WeChatPayOptions:AppId"],
                            MchId = _config["WeChatPayOptions:MchId"],
                            APIKey = _config["WeChatPayOptions:APIKey"],
                            APIv3Key = _config["WeChatPayOptions:APIv3Key"],
                            Certificate = _config["WeChatPayOptions:Certificate"],
                            // APIPrivateKey = _config["WeChatPayOptions:APIPrivateKey"],
                            WeChatPayPublicKey = _config["WeChatPayOptions:PublicKey"],
                            WeChatPayPublicKeyId = _config["WeChatPayOptions:PublicKeyId"],
                            RsaPublicKey = _config["WeChatPayOptions:RsaPublicKey"],
                            AppSecret = _config["WeChatPayOptions:AppSecret"],
                            CertificatePassword = _config["WeChatPayOptions:CertificatePassword"],
                            SubAppId = _config["WeChatPayOptions:SubAppId"],
                            SubMchId = _config["WeChatPayOptions:SubMchId"]
                        }
                    };
                };
            }
            //微信小程序的配置获取
            if (funcs.GetMiniProgramOptions == null)
            {
                IConfiguration config = app.ApplicationServices.GetRequiredService<IConfiguration>();
                IConfigurationSection wechatConfig = config.GetSection("WeChat");

                if (wechatConfig == null) throw new WeChatSdkException($"WeChat 为空，请检查配置");

                funcs.GetMiniProgramOptions = (app) =>
                {
                    var section = app.NotEmpty() ? $":{app}" : "";

                    IConfigurationSection _config = config.GetSection($"{WeChatConsts.CONFIG_SECTION_MINIPROGRAM_KEY}{section}");
                    if (_config == null) throw new WeChatSdkException($"{WeChatConsts.CONFIG_SECTION_MINIPROGRAM_KEY}{section} 为空，请检查配置");

                    return new WeChatMiniProgramOption()
                    {
                        AppId = _config["AppId"],
                        AppSecret = _config["AppSecret"],
                        WeChatPayOptions = new WeChatPayOptions
                        {
                            AppId = _config["WeChatPayOptions:AppId"],
                            MchId = _config["WeChatPayOptions:MchId"],
                            APIKey = _config["WeChatPayOptions:APIKey"],
                            APIv3Key = _config["WeChatPayOptions:APIv3Key"],
                            Certificate = _config["WeChatPayOptions:Certificate"],
                            // APIPrivateKey = _config["WeChatPayOptions:APIPrivateKey"],
                            WeChatPayPublicKey = _config["WeChatPayOptions:PublicKey"],
                            WeChatPayPublicKeyId = _config["WeChatPayOptions:PublicKeyId"],
                            RsaPublicKey = _config["WeChatPayOptions:RsaPublicKey"],
                            AppSecret = _config["WeChatPayOptions:AppSecret"],
                            CertificatePassword = _config["WeChatPayOptions:CertificatePassword"],
                            SubAppId = _config["WeChatPayOptions:SubAppId"],
                            SubMchId = _config["WeChatPayOptions:SubMchId"]
                        }
                    };
                };
            }

            return app;
        }

        /// <summary>
        /// 使用分布式缓存来存储AccessToken
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseWeChatDistributedCacheForAccessToken(this IApplicationBuilder app)
        {
            var funcs = app.ApplicationServices.GetRequiredService<WeChatFuncs>();
            var cache = app.ApplicationServices.GetRequiredService<IDistributedCache>();

            if (funcs.GetTicketByAppId == null)
            {
                funcs.GetTicketByAppId = (appid) => cache.GetString($"{WeChatConsts.PUBLICACCOUNT_CACHE_NAMESPACE}::JT::{appid}");
            }

            if (funcs.CacheTicket == null)
            {
                funcs.CacheTicket = (appid, ticket) =>
                {
                    if (string.IsNullOrEmpty(ticket))
                        throw new WeChatSdkException("ticket 为空，请检查IP白名单，安全域名等设置");

                    byte[] tokenBytes = Encoding.UTF8.GetBytes(ticket);
                    cache.Set($"{WeChatConsts.PUBLICACCOUNT_CACHE_NAMESPACE}::JT::{appid}", tokenBytes, new DistributedCacheEntryOptions()
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(115)
                    });
                };
            }

            if (funcs.GetAccessTokenByAppId == null)
            {
                funcs.GetAccessTokenByAppId = (appid) => cache.GetString($"{WeChatConsts.PUBLICACCOUNT_CACHE_NAMESPACE}::AT::{appid}");
            }

            if (funcs.CacheAccessToken == null)
            {
                funcs.CacheAccessToken = (appid, token) =>
                {
                    if (string.IsNullOrEmpty(token))
                        throw new WeChatSdkException("access_token 为空，请检查IP白名单，安全域名等设置");

                    byte[] tokenBytes = Encoding.UTF8.GetBytes(token);
                    cache.Set($"{WeChatConsts.PUBLICACCOUNT_CACHE_NAMESPACE}::AT::{appid}", tokenBytes, new DistributedCacheEntryOptions()
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(115)
                    });
                };
            }

            return app;
        }

        /// <summary>
        /// 确保成功执行
        /// </summary>
        /// <param name="apiResult"></param>
        public static void EnsureSuccess(this ApiResultBase apiResult)
        {
            if (!apiResult.IsSuccess())
            {
                throw new WeChatSdkException(apiResult.GetFriendlyMessage());
            }
        }
    }
}